package util;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Component;
import java.awt.Robot;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import model.Preference;
import model.Settings;

import org.apache.commons.io.FileUtils;
import org.json.simple.JSONObject;

import au.com.bytecode.opencsv.CSVReader;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.StreamException;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class PlayerUtilities {
	
	private static JSONObject UpdateStringJson = new JSONObject();
	private static int videoPasueTime = -100;
	private static Map<String,Integer> containerContent = new HashMap<String,Integer>();
	private static Map<String,Integer> ExpireContainerContent = new HashMap<String,Integer>();
	
	public static boolean saveStringToFile(String fileName, String inputString) {
		boolean saved = false;
		BufferedWriter bw = null;
		try {
			bw = new BufferedWriter(new FileWriter(fileName));
			
				bw.write(inputString);
				saved = true;
			
		} catch (IOException ex) {
			ex.printStackTrace();
			
			String classMethod = "util.PlayerUtilities in saveStringToFile()";
			LoggingUtils.logStart(classMethod);
			LoggingUtils.log(Level.SEVERE,ex.getMessage(),ex);
		}
		finally
		{
			try {
				bw.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				
				String classMethod = "util.PlayerUtilities in saveStringToFile() closing file";
				LoggingUtils.logStart(classMethod);
				LoggingUtils.log(Level.SEVERE,e.getMessage(),e);
			}
		}
		return saved;
	}

	public static String getStringFromFile(String fileName) {
		BufferedReader br = null;
		StringBuilder sb = new StringBuilder();
		try {
			br = new BufferedReader(new FileReader(fileName));

			try {
				String s;
				while ((s = br.readLine()) != null) {
					sb.append(s).append('\n');
				}
			} finally {
				br.close();
			}
		} catch (FileNotFoundException e) {
			// TODO add log for file not found
			e.printStackTrace();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		return sb.toString();
	}

	public static String convertToXML(Object obj) {
		XStream xstream = new XStream(new DomDriver());
		xstream.omitField(model.PlaylistRecord.class, "container");
		xstream.omitField(model.PlaylistRecord.class, "content");
		xstream.omitField(model.Container.class, "views");
		xstream.omitField(model.Player.class, "views");
		xstream.omitField(model.Preference.class, "views");
		return xstream.toXML(obj);
	}

	public static Object convertFromXML(String XMLString) {
		if (XMLString == null || XMLString.length() == 0) {
			return null;
		}

		Object obj = null;
		XStream xstream = new XStream(new DomDriver());
		try {
			obj = xstream.fromXML(XMLString);
		} catch (StreamException ex) {
			ex.printStackTrace();
			
			String classMethod = "util.PlayerUtilities in convertFromXML()";
			LoggingUtils.logStart(classMethod);
			LoggingUtils.log(Level.SEVERE,ex.getMessage() + classMethod,ex);
			
			return null;
		}
		return obj;
	}

	public static List<String[]> getArrayFromCSVFile(String fileName) {
		List<String[]> result = new ArrayList<String[]>();
		CSVReader reader = null;
		try {
			try {
				reader = new CSVReader(new FileReader(fileName));
				String[] nextLine;
				while ((nextLine = reader.readNext()) != null) {
					result.add(nextLine);
				}
			} finally {
				reader.close();
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		return result;
	}

	public static String convertCSVToXML(String fileName) {
		File csvFile = new File(fileName);
		if (!csvFile.exists()) {
			return "";
		}
		List<String[]> data = getArrayFromCSVFile(fileName);
		String[] fields = data.remove(0);
		List<Map<String, String>> objects = new ArrayList<Map<String, String>>();

		for (int i = 0; i < data.size(); i++) {
			Map<String, String> map = new HashMap<String, String>();
			String[] row = data.get(i);
			for (int j = 0; j < row.length; j++) {
				map.put(fields[j], row[j]);
			}
			objects.add(map);
		}

		XStream xstream = new XStream(new DomDriver());
		return xstream.toXML(objects);
	}

	public static boolean saveObjectToXMLFile(String fileName, Object obj) {
		return saveStringToFile(fileName, convertToXML(obj));
	}

	public static Object getObjectFromXMLFile(String fileName) {
		return convertFromXML(getStringFromFile(fileName));
	}

	public static Color getRandomColor() {
		Random random = new Random();
		Color randomColor = Color.getHSBColor(random.nextFloat(), 1.0F, 1.0F);
		return randomColor;
	}

	public static int scale(int number, double scale) {
		return (int) (number * scale);
	}

	public static boolean hasNetworkConnection() {
		if(!Preference.getInstance().isCheckUpdates())
			return false;
		
		try {
			Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
			while (interfaces.hasMoreElements()) {
				NetworkInterface nic = interfaces.nextElement();
				if (!nic.isLoopback() && nic.isUp()) {
					return true;
				}
			}
		} 
		catch(ConnectException e)
		{
			String classMethod = "util.PlayerUtilities in hasNetworkConnection()";
			LoggingUtils.logStart(classMethod);
			LoggingUtils.log(Level.SEVERE,e.getMessage() + classMethod,e);
		}
		catch (SocketException ex) {
			ex.printStackTrace();
			
			String classMethod = "util.PlayerUtilities in hasNetworkConnection()";
			LoggingUtils.logStart(classMethod);
			LoggingUtils.log(Level.SEVERE,ex.getMessage() + classMethod,ex);
		}
		catch(Exception e)
		{
			String classMethod = "util.PlayerUtilities in hasNetworkConnection()";
			LoggingUtils.logStart(classMethod);
			LoggingUtils.log(Level.SEVERE,e.getMessage() + classMethod,e);
		}
		return false;
	}

	public static final void copyInputStream(InputStream in, OutputStream out) throws IOException {
		byte[] buffer = new byte[1024];
		int len;

		while ((len = in.read(buffer)) >= 0) {
			out.write(buffer, 0, len);
		}

		in.close();
		out.close();
	}

	/*
	 * Extracting the folder collected from server resources.zip
	 */
	public static void unzip(File file, File dest) {
		if (file == null || dest == null) {
			return;
		}
		if (dest.isFile()) {
			return;
		}
		if (!dest.exists()) {
			dest.mkdir();
		}
		Enumeration entries;
		ZipFile zipFile;
		try {
			zipFile = new ZipFile(file);

			entries = zipFile.entries();
			while (entries.hasMoreElements()) {
				ZipEntry entry = (ZipEntry) entries.nextElement();

				if (entry.isDirectory()) {
					// Assume directories are stored parents first then
					(new File(dest.getPath() + File.separator + entry.getName())).mkdir();
					continue;
				}
				File destFile = new File(dest, entry.getName());

				File destFileParent = destFile.getParentFile();
				destFileParent.mkdirs();
				System.out.println("Extracting file: " + destFile.toString());
				copyInputStream(zipFile.getInputStream(entry), new BufferedOutputStream(new FileOutputStream(destFile)));
			}

			zipFile.close();
		} catch (ZipException ex) {
			ex.printStackTrace();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	public static void createDirectories() {
		List<String> directories = new ArrayList<String>();
		directories.add(Settings.IMAGE_DIRECTORY);
		directories.add(Settings.HTML_DIRECTORY);
		directories.add(Settings.VIDEO_DIRECTORY);
		directories.add(Settings.CSV_DIRECTORY);
		directories.add(Settings.XML_DIRECTORY);
		directories.add(Settings.CMD_DIRECTORY);
		if(!new File(Settings.LOG_DIRECTORY).exists())
		{
			System.out.println("Doesn't exists so creating");
			directories.add(Settings.LOG_DIRECTORY);
		}
		directories.add(Settings.TEST_DIRECTORY);
		directories.add(Settings.SQL_DIRECTORY);
		directories.add(Settings.SCRIPT_DIRECTORY);
		for (String dir : directories) {
			File d = new File(dir);
			if (!d.exists() || !d.isDirectory()) {
				d.mkdirs();
			}
		}
	}

	public static boolean recursiveDelete(String path) {
		File file = new File(path);
		boolean result;
		if (file.isFile()) {
			result = file.delete();
			if(result==false) {
				System.out.println("unable to delete " + file.getPath());
			}
			return result;
		} else if (file.isDirectory()) {
			boolean innerDeleted = true;
			for (String filePath : file.list()) {
				File f = new File(file, filePath);
				innerDeleted = recursiveDelete(f.getPath());
			}
			result = innerDeleted && file.delete();
			return result;
		} else {
			return false;
		}
	}

	public static void recursiveDeleteOnExit(String path) {
		File file = new File(path);
		if (file.isFile()) {
			file.deleteOnExit();
			return;
		} else if (file.isDirectory()) {
			for (String filePath : file.list()) {
				File f = new File(file, filePath);
				recursiveDeleteOnExit(f.getPath());
			}
			file.deleteOnExit();
		}
	}

	public static boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i = 0; i < children.length; i++) {
				boolean success = deleteDir(new File(dir, children[i]));
				if (!success) {
					return false;
				}
			}
		}

		// The directory is now empty so delete it
		return dir.delete();
	}

	public static String getRemoteImageDirectoryForCurrentBox() {
		return Settings.DMB_DOMAIN + "/webtool/boxdata/" + Preference.getInstance().getBoxID() + "/images/";
	}

	public static void prepareSamplePlayerXMLDataForTesting() throws IOException {
		FileUtils.copyDirectory(new File("backup/videos"), new File("resources/videos"));
		FileUtils.copyDirectory(new File("backup/images"), new File("resources/images"));
		FileUtils.copyDirectory(new File("backup/xml"), new File("resources/xml"));
	}

	public static void moveMouse(int i, int j) {
		try {
			Robot r = new Robot();
			r.mouseMove(i, j);
		} catch (AWTException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void log(String message) {

	}

	public static void deleteOldLogFiles() {
		File logDir = new File(Settings.LOG_DIRECTORY);
		if (!logDir.isDirectory()) {
			return;
		}
		File[] logFiles = logDir.listFiles();
		int millisecondsInADay = 24 * 60 * 60 * 1000;
		int numDays = Preference.getInstance().getNumDaysToKeepLog();
		for (File logFile : logFiles) {
			if (System.currentTimeMillis() - millisecondsInADay * numDays > logFile.lastModified()) {
				logFile.delete();
			}
		}
	}

	public static String getTodayDateString() {
		Calendar c = Calendar.getInstance();
		Integer date = new Integer(c.get(Calendar.YEAR) * 10000 + (c.get(Calendar.MONTH) + 1) * 100
				+ c.get(Calendar.DAY_OF_MONTH));
		return date.toString();
	}
	
	public static boolean deleteResourcesFolder() {
		try {
			File resourcesFolder = new File(Settings.RESOURCES_DIRECTORY);
			org.apache.commons.io.FileUtils.deleteDirectory(resourcesFolder);
			return resourcesFolder.exists();
		} catch (IOException e) {
			System.err.println("unable to delete the resources folder and reset the player.");
			e.printStackTrace();
			
			String classMethod = "util.PlayerUtilities in .deleteResourcesFolder()";
			LoggingUtils.logStart(classMethod);
			LoggingUtils.log(Level.SEVERE,e.getMessage() + classMethod,e);
		}
		return false;
	}
	
	public static void testComponent(final Component comp) {
		SwingUtilities.invokeLater(new Runnable(){

			@Override
			public void run() {
				JFrame frame = new JFrame("test");
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.getContentPane().add(comp);
				frame.pack();
				frame.setVisible(true);
			}
		});
	}

    public static void copyFromJarToDirectory(String filePathInJar, String destinationFileName) {
			InputStream stream = ClassLoader.getSystemClassLoader().getResourceAsStream(filePathInJar);
			if(stream==null) {
				System.out.println("unable to locate resource in the jar file with path: "+ filePathInJar);
			} else {
				InputStreamReader isr = new InputStreamReader(stream);
				BufferedReader br = new BufferedReader(isr);
				StringBuilder sb = new StringBuilder();
				String line = null;
				try {
					while(null !=(line = br.readLine())) {
						sb.append(line).append("\n");
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				PlayerUtilities.saveStringToFile(destinationFileName, sb.toString());
			}
    }
    
   public static boolean isBrowserSupported() {
	   return true;
	   
		/*if(Platform.getPlatform()==platform.Platform.LINUX) {
			return true;
		}
		return false;*/
	}

	public static JSONObject getUpdateStringJson() {
		return UpdateStringJson;
	}

	public static void setUpdateStringJson(JSONObject updateStringJson) {
		UpdateStringJson = updateStringJson;
	}
	
	@SuppressWarnings("unchecked")
	public static void setUpdateStringJson(String key, int value) {
		try {
			if(!key.equals(""))
				UpdateStringJson.put(key, value);
		} catch (Exception e) {
			LoggingUtils.log(Level.SEVERE, e.getMessage(),e);
		}
	}
	
	@SuppressWarnings("unchecked")
	public static void setUpdateStringJson(String key, String value) {
		try {
			if(!key.equals("") && !value.equals(""))
				UpdateStringJson.put(key, value);
		} catch (Exception e) {
			LoggingUtils.log(Level.SEVERE, e.getMessage(),e);
		}
	}
	
	@SuppressWarnings("unchecked")
	public static void setUpdateStringJson(String key, List<Integer> value) {
		try 
		{
			if(value.size() > 0 && !key.equals(""))
			{
				System.out.println("FROM UTILITES "+value.toString());
				UpdateStringJson.put(key, value);
			}
		}catch (Exception e) {
			LoggingUtils.log(Level.SEVERE, e.getMessage(),e);
		}
	}
	
	@SuppressWarnings("unchecked")
	public static void setUpdateStringJsonString(String key, List<String> value) {
		try 
		{
			if(value.size() > 0 && !key.equals(""))
			{
				UpdateStringJson.put(key, value);
			}
		}catch (Exception e) {
			LoggingUtils.log(Level.SEVERE, e.getMessage(),e);
		}
	}
	
	public static void resetUpdateStringJson() {
		UpdateStringJson = new JSONObject();
	}
	
	@SuppressWarnings("unchecked")
	public static void saveJsonToFile(String key,int value)
	{
		try {
			
			if(!key.equals(""))
			{	
				JSONObject saveJosn = new JSONObject();
				saveJosn.put(key, value);
				PlayerUtilities.saveStringToFile(Settings.REPLY_TO_FILENAME, saveJosn.toJSONString());
			}
		}catch (Exception e) {
			LoggingUtils.log(Level.SEVERE, e.getMessage(),e);
		}
	}

	public static int getVideoPasueTime() {
		return videoPasueTime;
	}

	public static void setVideoPasueTime(int videoPasueTime) {
		PlayerUtilities.videoPasueTime = videoPasueTime;
	}

	public static Map<String, Integer> getContainerContent() {
		return containerContent;
	}

	public static void setContainerContent(Map<String, Integer> containerContent) {
		PlayerUtilities.containerContent = containerContent;
	}
	
	public static void setContainerContentValue(String key)
	{
		if(PlayerUtilities.getContainerContent().containsKey(key))
		{
			int value = PlayerUtilities.getContainerContent().get(key);
			PlayerUtilities.getContainerContent().put(key, value+1);
		}
		else
		{
			PlayerUtilities.getContainerContent().put(key, 1);
		}
	}
	
	public static void resetContainerContent()
	{
		containerContent = new HashMap<String,Integer>(); 
	}

	public static Map<String, Integer> getExpireContainerContent() {
		return ExpireContainerContent;
	}

	public static void setExpireContainerContent(
			Map<String, Integer> expireContainerContent) {
		ExpireContainerContent = expireContainerContent;
	}
	
	public static void setExpireContainerContentValue(String key)
	{
		if(PlayerUtilities.getExpireContainerContent().containsKey(key))
		{
			int value = PlayerUtilities.getExpireContainerContent().get(key);
			PlayerUtilities.getExpireContainerContent().put(key, value+1);
		}
		else
		{
			PlayerUtilities.getExpireContainerContent().put(key, 1);
		}
	}
	
	public static void setExpireContainerContentValue(String key, int value)
	{
		PlayerUtilities.getExpireContainerContent().put(key, value);
	}
	
	public static void resetExpireContainerContent()
	{
		ExpireContainerContent = new HashMap<String,Integer>(); 
	}
	
}
